package com.naspan.common.aspectj;

import com.naspan.common.annotation.GlobalInterceptor;
import com.naspan.common.annotation.VerifyParam;
import com.naspan.common.exception.bizExceptionHandle;
import com.naspan.entity.vo.LoginUserVo;
import com.naspan.utils.ServletUtils;
import com.naspan.utils.VerifyUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component("globalOperationAspect")
public class GlobalOperationAspect {
    public static final Logger logger = LoggerFactory.getLogger(GlobalOperationAspect.class);

    public static final String[] TYPE_BASE = {"java.lang.String", "java.lang.Integer", "java.lang.Long" };

    @Pointcut("@annotation(com.naspan.common.annotation.GlobalInterceptor)")
    private void requestInterceptor() {

    }

    @Before("requestInterceptor()")
    public void interceptorDo(JoinPoint point) {
        try {
            Object target = point.getTarget();
            Object[] args = point.getArgs();
            String methodName = point.getSignature().getName();
            Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
            Method method = target.getClass().getMethod(methodName, parameterTypes);
            GlobalInterceptor annotation = method.getAnnotation(GlobalInterceptor.class);
            if (annotation == null) {
                return;
            }
            if (annotation.checkParam()) {
                validateParams(method, args);
            }
            if(annotation.checkLogin()){
                LoginUserVo user = ServletUtils.getUser();
                if(user == null){
                    throw new bizExceptionHandle("登录异常");
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }


    /**
     * 验证参数的合法性
     * @param method 方法对象
     * @param args   方法参数数组
     */
    private void validateParams(Method method, Object[] args) {
        // 获取方法的参数列表
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Object value = args[i];
            // 获取参数上的注解
            VerifyParam verifyParam = parameter.getAnnotation(VerifyParam.class);
            if (verifyParam == null) {
                continue;
            }
            if (ArrayUtils.contains(TYPE_BASE, parameter.getParameterizedType().getTypeName())) {
                checkValue(verifyParam, value);
            } else {
                checkObjValue(parameter,value);
            }
        }
    }

    private void checkObjValue(Parameter parameter, Object value) {
        try {
            String typeName = parameter.getParameterizedType().getTypeName();
            Class clazz = Class.forName(typeName);
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                VerifyParam fieldAnnotation = field.getAnnotation(VerifyParam.class);
                if (fieldAnnotation==null) {
                    continue;
                }
                field.setAccessible(true);
                Object resultValue = field.get(value);
                checkValue(fieldAnnotation,resultValue);
            }
        } catch (bizExceptionHandle e) {
            logger.error("检验参数失败",e);
            throw e;
        }catch (Exception e) {
            logger.error("检验参数失败",e);
            throw new bizExceptionHandle("检验参数失败");
        }
    }
    /**
     * 检查对象类型值的合法性
     *
     * @param verifyParam 验证参数
     * @param value       值
     */


    /**
     * 检查基本数据类型值的合法性
     *
     * @param verifyParam 验证参数
     * @param value       值
     */
    private void checkValue(VerifyParam verifyParam, Object value) {
        // 判断值是否为空
        boolean isEmpty = value == null || StringUtils.isEmpty(value.toString());
        // 获取值的长度
        int valueLength = value == null ? 0 : value.toString().length();

        // 如果该参数是必传的，但是值为空，则抛出异常
        if (isEmpty && verifyParam.require()) {
            throw new bizExceptionHandle("参数错误");
        }

        // 如果值不为空，且长度不在指定的范围内，则抛出异常
        if (!isEmpty && (verifyParam.min() != -1 && verifyParam.min() > valueLength || verifyParam.max() != -1 && verifyParam.max() < valueLength)) {
            throw new bizExceptionHandle("参数错误");
        }

        // 如果值不为空，且需要进行正则表达式验证，但是验证不通过，则抛出异常
        if (!isEmpty && !StringUtils.isEmpty(verifyParam.regex().getRegex()) && !VerifyUtils.verify(verifyParam.regex(), String.valueOf(value))) {
            throw new bizExceptionHandle("参数错误");
        }
    }
}
